﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace LittleBee.Utils
{
	/*	public enum EventType
		{
			/// <summary>
			/// event type for object
			/// </summary>
			Contruct = 1,
			Initialize,
			RunLoop,
			Exit,

			//SetPointersValue,

			CustomEvent1 = 1001,
			CustomEvent2 = 1002,
			CustomEvent3 = 1003,
			CustomEvent4 = 1004,
			CustomEvent5 = 1005,
		}

		public class EventLoopArgs : EventArgs
		{
			public EventLoopArgs(EventType type, bool blBroadcast = false)
			{
				Init(type, null, null, null, blBroadcast);
			}

			public EventLoopArgs(EventType type, JToken data, bool blBroadcast = false)
			{
				Init(type, data, null, null, blBroadcast);
			}

			public EventLoopArgs(EventType type, LBUUID sender, bool blBroadcast = false)
			{
				Init(type, null, sender, null, blBroadcast);
			}

			public EventLoopArgs(EventType type, JToken data, LBUUID sender, bool blBroadcast = false)
			{
				Init(type, data, sender, null, blBroadcast);
			}

			public EventLoopArgs(EventType type, LBUUID sender, LBUUID recver, bool blBroadcast = false)
			{
				Init(type, null, sender, recver, blBroadcast);
			}

			public EventLoopArgs(EventType type, JToken data, LBUUID sender, LBUUID recver, bool blBroadcast = false)
			{
				Init(type, data, sender, recver, blBroadcast);
			}

			private void Init(EventType type, JToken data, LBUUID sender, LBUUID recver, bool blBroadcast)
			{
				Recver = recver;
				Sender = sender;
				Data = data;

				EvType = type;
				BroadcastEvent = blBroadcast;
			}

			public LBUUID Sender { get; private set; } = null;
			public LBUUID Recver { get; private set; } = null;
			public EventType EvType { get; private set; }
			public bool BroadcastEvent { get; private set; } = false;
			public JToken Data { get; private set; }
		}
	*/

	public interface IEventLoop
	{
		LBUUID UUID { get; }
		//int LoopEvent(EventLoopArgs args);
	}

	public class LBUUID : IEquatable<LBUUID>
	{
		static LBUUID()
		{
			//SiteConfiguration siteConfig = (SiteConfiguration)ConfigurationManager.GetSection("SiteConfiguration");
			AppConfigSeciton section = new AppConfigSeciton("SiteConfiguration");

			LocalServerID = UInt64.Parse(section.GetValue("ServerID", "0"));
			LocalSiteID = ushort.Parse(section.GetValue("SiteID", "0"));
		}

		public LBUUID(Int64 oid)
		{
			ObjectID = oid;
		}

		/// <summary>
		/// local server id: 6bytes
		/// </summary>
		public static UInt64 LocalServerID { get; set; } = 0;
		/// <summary>
		/// local site id: 2bytes
		/// </summary>
		public static ushort LocalSiteID { get; set; } = 0;

		/// <summary>
		/// Server ID: 6bytes
		/// </summary>
		public UInt64 ServerID { get; set; } = LocalServerID & 0xffffffffffff;

		/// <summary>
		/// Site ID: 2 bytes
		/// </summary>
		public ushort SiteID { get; set; } = (ushort)LocalSiteID;

		/// <summary>
		/// Object ID: 8bytes,此id一般都是64位的数据库自增字段
		/// </summary>
		public Int64 ObjectID { get; set; } = 0;

		private string Value
		{
			get
			{
				StringBuilder sb = new StringBuilder();
				return sb.Append(ServerID.ToString("X12")).Append(SiteID.ToString("X4")).Append(ObjectID.ToString("X16")).ToString();
			}
		}

		public override string ToString()
		{
			return Value.ToString();
		}

		public bool Equals(LBUUID? other) =>
			Value == other!.Value;

		public override bool Equals(object? obj) =>
			obj is LBUUID other && Equals(other);

		public override int GetHashCode()
		{
			return base.GetHashCode();
		}
	}

/*	public enum EventLoopRunningStatus
	{
		Constructing,
		Loading,
		Initializing,
		Running,
		Pausing,
		Stopping,
		UnLoading,
		Exiting,
		Destructing,
	}
*/
	public abstract class EventLoop : IEventLoop, IDisposable
	{
		private Task? _oTask;
		readonly CancellationTokenSource _cancelSource = new CancellationTokenSource();
		readonly ManualResetEvent _rePause = new ManualResetEvent(true);

		private LBUUID _uuid;

		/// <summary>
		/// UInt32.MaxValue is mean that the interval is infinate
		/// </summary>
		public Int32 UpdateInterval { get; set; } = Timeout.Infinite;

		public EventLoop(Int64 oid)
		{
			_uuid = new LBUUID(oid);
			Construct();
		}

		protected abstract bool IsFirstLoaded { get; set; }
		//protected bool IsFirstRunning { get; private set; } = true;

		public LBUUID UUID
		{
			get { return _uuid; }
			set
			{ 
				_uuid = value; 
				RegisterEventLoopObject(this);
			}
		}

		public void Start()
		{
			CancellationToken _cancelToken = _cancelSource.Token;
			_oTask = Task.Run(() =>
			{
				try
				{
					while (true)
					{
						// 
						if (_cancelToken.IsCancellationRequested)
							return;

						/// _rePause.Reset() : pause cell to run
						/// _rePause.Set() : restart cell to run
						_rePause.WaitOne();

						OnRunLoop();
						Thread.Sleep(UpdateInterval);
					}
				}
				catch (Exception ex)
				{
					Console.WriteLine($"Exception: {ex.Message} : {ex.StackTrace}");
				}
			}, _cancelToken);

			//RunningStatus = EventLoopRunningStatus.Constructing;
			//PutEvent(EventType.Contruct, null, UUID);
		}

		public void Stop()
		{
			OnStop();
			_cancelSource.Cancel();
		}

		public void Pause()
		{
			OnPause();
			_rePause.Reset();
		}

		public void Restart()
		{
			OnRestart();
			_rePause.Set();
		}

		protected virtual void Construct()
		{
			OnConstruct();
		}

		public virtual void Initialize()
		{
			OnInitialize();
		}
		public virtual void finalize()
		{
			OnUninitialize();
		}

		public abstract void OnPause();

		public abstract void OnRestart();

		public abstract void OnStop();

		public abstract void OnInitialize();

		public abstract void OnUninitialize();

		public abstract void OnConstruct();

		public abstract void OnRunLoop();

		public abstract void OnFirstLoad();

		protected abstract bool OnCheckPointersValue(JArray joPointers);
		//protected abstract void OnPointerPropertyChanged(object sender, PointerPropertyChangedEventArgs args);
		//protected abstract bool OnPointerPropertyChanging(object sender, PointerPropertyChangingEventArgs args);

		public virtual void Dispose() { }

		private static readonly Dictionary<LBUUID, EventLoop> _dctEvLoopObject = new Dictionary<LBUUID, EventLoop>();
		private static readonly object _oEvLoopObjectLock = new object();
		private static void RegisterEventLoopObject(EventLoop oEvLoop)
		{
			lock (_oEvLoopObjectLock)
			{
				_dctEvLoopObject.Add(oEvLoop.UUID, oEvLoop);
			}
		}
	}
}
